package com.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.StringUtil;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.util.UUID;

/**
 * netty httpclient 处理器
 *
 * @author gjj
 */
public class HttpClientHandler extends SimpleChannelInboundHandler<HttpObject> {


    private StringBuffer jsonBuilder = new StringBuffer();

    private StringBuffer failBuilder = new StringBuffer();

    private ChannelPromise channelPromise;

    private String requestId;

    private String filePath;

    private String fileName;

    private File file;


    @Override
    public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
        try {
            if (msg instanceof HttpResponse) {
                HttpResponse response = (HttpResponse) msg;
                HttpHeaders headers = response.headers();
                requestId = headers.get("requestId");
                fileName = headers.get("fileName");
            } else if (msg instanceof HttpContent) {
                HttpContent chunk = (HttpContent) msg;
                if (chunk instanceof LastHttpContent) {
                    ByteBuf content = chunk.content();
                    if (requestId.endsWith("true")) {
                    } else {
                        String json = content.toString(CharsetUtil.UTF_8);
                        jsonBuilder.append(json);
                    }
                    channelPromise.setSuccess();
                } else {
                    ByteBuf content = chunk.content();
                    if (requestId.endsWith("true")) {
                        if (file == null) {
                            file = new File(filePath + "/" + fileName);
                            if (!file.exists()) {
                                file.createNewFile();
                            }
                        }
                        byte[] dst = new byte[content.readableBytes()];
                        content.readBytes(dst);
                        dealFile(dst);
                    } else {
                        String json = content.toString(CharsetUtil.UTF_8);
                        jsonBuilder.append(json);
                    }

                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            String message = e.getCause() != null ? e.getCause().getMessage() : e.getMessage();
            failBuilder.append(message);
        }

    }


    private void dealFile(byte[] dst) throws Exception {
        while (true) {
            try {
                RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
                randomAccessFile.seek(file.length());
                randomAccessFile.write(dst);
                randomAccessFile.close();
                break;
            }catch (FileNotFoundException e){
                continue;
            }
        }

    }

    public void setChannelPromise(ChannelPromise channelPromise) {
        this.channelPromise = channelPromise;
    }

    public String getResult() {
        return jsonBuilder.toString();
    }

    public String getFailResult() {
        return failBuilder.toString();
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.channel().close();
        failBuilder.append(cause.getMessage());
    }


    public static Object call(HttpRequest request,
                              HttpPostRequestEncoder encoder,
                              Channel channel, boolean isFile, String filePath) throws Exception {
        String uuid = UUID.randomUUID().toString() + isFile;
        HttpClientHandler handler = (HttpClientHandler) channel.pipeline().get("handler");
        ChannelPromise channelPromise = channel.newPromise();
        handler.setChannelPromise(channelPromise);
        if (!StringUtil.isNullOrEmpty(filePath)) {
            handler.setFilePath(filePath);
        }
        HttpHeaders headers = request.headers();
        headers.set("requestId", uuid);
        channel.write(request);
        if (encoder != null) {
            if (encoder.isChunked()) {
                channel.write(encoder);
            }
        }
        channel.flush();
        channelPromise.await();
        String failResult = handler.getFailResult();
        String result = handler.getResult();
        if (!StringUtil.isNullOrEmpty(failResult)) {
            throw new RuntimeException(failResult);
        }
        return result;
    }


}
